package com.filldream.fastboot.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.filldream.fastboot.base.entity.Role;
import com.filldream.fastboot.base.entity.SystemUser;
import com.filldream.fastboot.base.mapper.SystemUserMapper;
import com.filldream.fastboot.base.request.pc.systemUser.ModifyPasswordSTO;
import com.filldream.fastboot.base.request.pc.systemUser.SystemLoginSTO;
import com.filldream.fastboot.base.request.pc.systemUser.SystemUserListSTO;
import com.filldream.fastboot.base.response.pc.MenusDTO;
import com.filldream.fastboot.base.response.pc.SystemLoginDTO;
import com.filldream.fastboot.base.response.pc.systemUser.SysUserPageDTO;
import com.filldream.fastboot.common.constant.FinalStr;
import com.filldream.fastboot.common.entity.*;
import com.filldream.fastboot.common.util.*;
import com.filldream.fastboot.core.LoginHolder;
import com.filldream.fastboot.core.cache.CacheMap;
import com.filldream.fastboot.core.cache.CacheObj;
import com.filldream.fastboot.core.cache.CacheUtil;
import com.filldream.fastboot.core.manager.*;
import com.filldream.fastboot.core.service.SystemUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.List;

@Service
@Transactional(rollbackFor = Exception.class)
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {

    @Resource
    private RoleMenuManager roleMenuManager;

    @Resource
    private RoleManager roleManager;

    @Resource
    private DeptManager deptManager;


    @Override
    public R<SystemLoginDTO> doLogin(SystemLoginSTO systemLoginSTO, String sessionId) {
        Assert.checkPwd(  systemLoginSTO.getPassword() );
        String account = systemLoginSTO.getAccount();
        String password = systemLoginSTO.getPassword();
        SystemLoginDTO systemLoginDTO = null;

        R<LoginEx> check = LoginSafeUtil.check(account);
        if( !check.isOk() ){
            return R.fail(check.getMsg()).put("need",true);
        }

        LoginEx loginEx = check.getData();
        //本次是否需要校验验证码
        if(loginEx.getNowIsNeed()){
            B b = CheckCodeUtil.checkCaptcha(systemLoginSTO.getCaptchaCode(),systemLoginSTO.getCaptchaKey());
            if( !b.isOk() ){
                return R.createError(ErrorCode.BASE_ERR.reMsg(b.getMsg())).put("need",true);
            }
        }


        //账号登陆
        password = EncryptUtil.md5Encode(password, FinalStr.getPwdKey());
        List<SystemUser> systemUserList = list(
                new QueryWrapper<SystemUser>().eq("account",account)
                        .eq("password",password).eq("is_del",0)
        );
        if (systemUserList.isEmpty()) {
            R<LoginEx> limit = LoginSafeUtil.limit(loginEx, account);
            return R.createError(ErrorCode.PASSWORD_ERROR.reMsg()).put("need",limit.getData().getNextIsNeed() );
        }
        LoginSafeUtil.unseal(account);
        SystemUser systemUser = systemUserList.get(0);
        if (systemUser.getStatus().equals(0)) {
            return R.diy(ErrorCode.AUTH_ERR, "当前管理员已被禁用，请通知(上级/超级)管理员");
        }
        if ( systemUser.getRoleId() < 1 ) {
            return R.diy(ErrorCode.AUTH_ERR, "当前管理员没有权限");
        }
        systemLoginDTO = new SystemLoginDTO();
        BeanUtils.copyProperties(systemUser, systemLoginDTO);
        systemLoginDTO.setId(systemUser.getId().longValue());
        systemLoginDTO.setToken(sessionId);
        //细分权限
        MenusDTO menu = roleMenuManager.getRoleSelectedMenu(systemUser.getRoleId());
        if (menu.getMenuList().isEmpty()) {
            return R.fail("您暂无权限登陆");
        }
        Role role = roleManager.getById(systemLoginDTO.getRoleId());
        Assert.isNull( role ,ErrorCode.AUTH_ERR.reMsg(":当前管理员的角色不存在"));
        systemLoginDTO.setRole(role);
        String pcToken = sessionId+RandomUtil.randAlphaNumString(15);
        CacheUtil.cachePcToken(systemLoginDTO, pcToken,menu.getCodes());
        systemLoginDTO.setAccess(menu);
        return R.successd(systemLoginDTO);
    }

    @Override
    public B loginOut(HttpServletRequest request, HttpSession session, HttpServletResponse response) {
        session.invalidate();
        String token = RequestContext.getToken();
        Long pcUserId = LoginHolder.getPcUserId();
        String tokenListKey = CacheMap.getKey(CacheMap.SYSTEM_USER_ID, pcUserId);
        String tokenDetailKey = CacheMap.getKey(CacheMap.SYSTEM_USER_TOKEN, token);

        try( Jedis jedis = CacheUtil.getCacheJedis() ){
            //删除用户登录详情
            jedis.del( tokenDetailKey );
            //允许多处登录仅删除token及用户详情
            if( CacheUtil.getPcMu() ){
                jedis.srem(tokenListKey, token);
            }else{
                //仅允许同时登录一个,全部删除
                jedis.del( tokenListKey );
            }
        }
       return B.success();
    }

    @Override
    public B modifyPassword(ModifyPasswordSTO modifyPasswordSTO) {
        modifyPasswordSTO.setId(null);
        String oldPassword = modifyPasswordSTO.getOldPassword();
        String newPassword = modifyPasswordSTO.getNewPassword();
        Assert.checkPwd( oldPassword );
        Assert.checkPwd( newPassword );
        Assert.isEmpty( oldPassword, ErrorCode.BASE_ERR.reMsg("原密码不能为空") );
        Assert.isEmpty( newPassword, ErrorCode.BASE_ERR.reMsg("新密码不能为空") );

        //校验原密码是否正确
        String checkPassword = EncryptUtil.md5Encode(oldPassword, FinalStr.getPwdKey());
        Long pcUserId = LoginHolder.getPcUserId();

        Long count = count(
                new QueryWrapper<SystemUser>().eq("id", pcUserId)
                        .eq("password", checkPassword).eq("is_del", 0)
        );
        Assert.isBoolean( count.equals(0L), ErrorCode.BASE_ERR.reMsg("原密码错误") );


        SystemUser systemUser = new SystemUser();
        systemUser.setId(pcUserId);
        systemUser.setPassword( EncryptUtil.md5Encode(newPassword, FinalStr.getPwdKey()) );
        return B.checkSuccess( updateById(systemUser) );
    }

    @Override
    public P systemUserList(SystemUserListSTO systemUserListSTO) {
        SystemLoginDTO nowUser = LoginHolder.getPcUser();
        Long linkId = nowUser.getLinkId();

        systemUserListSTO.setLinkId(linkId != null && !linkId.equals(1L) ? linkId : null);

        Page<SysUserPageDTO> page = systemUserListSTO.page();
        List<SysUserPageDTO> systemUsers = baseMapper.pageList(page, systemUserListSTO);
        page.setRecords(systemUsers);
        return P.autoSuccess(page);
    }


    @Override
    public R<SystemUser> addSystemUser(SystemUser systemUser) {
        Assert.checkPwd( systemUser.getPassword() );
        //判断账号是否重复
        long hasRepeat = hasRepeat(systemUser.getAccount());
        Assert.checkBoolean( hasRepeat == 0 ,ErrorCode.USER_EXIST.reMsg() );
        systemUser.setPassword( EncryptUtil.md5Encode( systemUser.getPassword(),FinalStr.getPwdKey() ) );

        //部门
        Long linkId = deptManager.getParentCompanyId(systemUser.getDeptId());
        systemUser.setLinkId(linkId);

        save(systemUser);
        systemUser.setPassword(null);
        return R.autoSuccess( systemUser );
    }

    @Override
    public B modifySystemUser(SystemUser systemUser) {

        SystemUser old = baseMapper.selectById(systemUser.getId());
        Assert.isEmpty(old,"用户不存在");

        Assert.isBoolean(systemUser.getId().equals(1L) && !LoginHolder.getPcUserId().equals(1L),ErrorCode.BASE_ERR.reMsg("您不能修改超级管理员的信息"));

        //如果修改账号则看下是否有重复账号
        if( StringUtils.isNotBlank(systemUser.getAccount()) && !systemUser.getAccount().equals(old.getAccount())  ){
            Long hasRepeat = hasRepeat(systemUser.getAccount());
            Assert.checkBoolean( hasRepeat.equals(0L) ,ErrorCode.USER_EXIST.reMsg() );
        }

        boolean needLoginOut = false;

        //修改密码
        if( StringUtils.isNotBlank( systemUser.getPassword() ) ){
            Assert.checkPwd(systemUser.getPassword());
            systemUser.setPassword( EncryptUtil.md5Encode( systemUser.getPassword(),FinalStr.getPwdKey() ) );
            needLoginOut = true;
        }
        //修改状态 或 删除
        Integer status = systemUser.getStatus();
        if ( status != null && status.equals(0)){
            needLoginOut = true;
        }
        if ( systemUser.getIsDel() != null && systemUser.getIsDel().equals(1)){
            needLoginOut = true;
        }

        //部门
        if( !systemUser.getId().equals(1L) ){
            Long linkId = deptManager.getParentCompanyId(systemUser.getDeptId());
            systemUser.setLinkId(linkId);
        }else{
            systemUser.setLinkId(0L);
            systemUser.setDeptId(null);
            systemUser.setPostId(null);
        }


        boolean b = updateById(systemUser);
        if(needLoginOut && b){
            CacheUtil.clearPcAllToken(systemUser.getId());
        }
        return B.checkSuccess( b );
    }

    @Override
    public B modifySystemUserStatus(Long id, Integer status) {
        //判断是否是超级管理员
        if( id.equals(1L) && status.equals(0) ){
            return B.fail("超级管理员不允许禁用!");
        }
        SystemUser systemUser = new SystemUser();
        systemUser.setId( id );
        systemUser.setStatus( status );
        systemUser.setUpdateTime(new Date());
        if( status.equals(0) ){
            CacheUtil.clearPcAllToken(id);
        }
        return B.checkSuccess(updateById(systemUser));
    }

    @Override
    public R<Boolean> validCaptcha(String account) {
        CacheObj<LoginEx> cache = CacheUtil.getCache(CacheMap.LOGIN_SAFE, LoginEx.class, account);
        LoginEx data = cache.getData();
        if( data == null ){
            return R.successd(false);
        }
        data.initNextIsNeed();
        data.initNowIsNeed();
        data.initType();
        data.initCanLoginTime();
        data.initNextIsNeedWhenError();
        return R.successd(data.getNowIsNeed());
    }

    @Override
    public B resetPwd(ModifyPasswordSTO modifyPasswordSTO) {
        Assert.isEmpty(modifyPasswordSTO.getId(),"用户ID不能为空");
        Assert.isBoolean(modifyPasswordSTO.getId().equals(1L) && !LoginHolder.getPcUserId().equals(1L),ErrorCode.BASE_ERR.reMsg("您不能修改超级管理员的密码"));
        String newPassword = modifyPasswordSTO.getNewPassword();
        Assert.checkPwd( newPassword );
        Assert.isEmpty( newPassword, ErrorCode.BASE_ERR.reMsg("新密码不能为空") );

        SystemUser systemUser = new SystemUser();
        systemUser.setId(modifyPasswordSTO.getId());
        systemUser.setPassword(   EncryptUtil.md5Encode(newPassword, FinalStr.getPwdKey()) );

        return B.checkSuccess(updateById(systemUser));
    }

    //判断账号是否重复
    public long hasRepeat(String account){
        return  count(new QueryWrapper<SystemUser>().eq("account", account)
                .eq("is_del", 0)
        );
    }


}
